<?php

namespace App\Core;

use Exception;

class JWT
{
    private static function getSecret(): string
    {
        return $_ENV['JWT_SECRET'] ?? 'your-secret-key-here';
    }

    private static function getExpiration(): int
    {
        return (int) ($_ENV['JWT_EXPIRATION'] ?? 3600);
    }

    public static function encode(array $payload): string
    {
        $header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
        $payload['iat'] = time();
        $payload['exp'] = time() + self::getExpiration();
        $payload = json_encode($payload);
        
        $base64Header = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
        $base64Payload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
        
        $signature = hash_hmac('sha256', $base64Header . "." . $base64Payload, self::getSecret(), true);
        $base64Signature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
        
        return $base64Header . "." . $base64Payload . "." . $base64Signature;
    }

    public static function decode(string $token): ?object
    {
        try {
            $parts = explode('.', $token);
            if (count($parts) !== 3) {
                return null;
            }
            
            $header = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $parts[0])), true);
            $payload = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $parts[1])), true);
            
            if (!$header || !$payload) {
                return null;
            }
            
            // 验证签名
            $signature = hash_hmac('sha256', $parts[0] . "." . $parts[1], self::getSecret(), true);
            $expectedSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
            
            if (!hash_equals($expectedSignature, $parts[2])) {
                return null;
            }
            
            // 检查过期时间
            if (isset($payload['exp']) && $payload['exp'] < time()) {
                return null;
            }
            
            return (object) $payload;
        } catch (Exception $e) {
            return null;
        }
    }

    public static function verify(string $token): bool
    {
        return self::decode($token) !== null;
    }
}

